package zxs.sino.elite.hub.service.app.impl;

import cn.hutool.core.date.DateTime;
import co.elastic.clients.elasticsearch._types.Result;
import co.elastic.clients.elasticsearch.core.IndexResponse;
import co.elastic.clients.elasticsearch.core.DeleteResponse;


import lombok.RequiredArgsConstructor;

import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.data.mongodb.core.MongoTemplate;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import org.springframework.stereotype.Service;
import java.io.IOException;
import com.github.yulichang.base.MPJBaseServiceImpl;
import org.springframework.transaction.annotation.Transactional;
import zxs.sino.elite.hub.constant.EsConstant;
import zxs.sino.elite.hub.enums.article.ArticleType;
import zxs.sino.elite.hub.exception.BizCodeEnums;
import zxs.sino.elite.hub.exception.RRException;
import zxs.sino.elite.hub.mapper.app.UserMapper;
import zxs.sino.elite.hub.model.app.ArticleMongoEntity;
import zxs.sino.elite.hub.model.app.UserEntity;
import zxs.sino.elite.hub.model.form.ArticleForm;
import zxs.sino.elite.hub.model.vo.app.ArticleVo;

import zxs.sino.elite.hub.mapper.app.ArticleMapper;
import zxs.sino.elite.hub.model.app.ArticleEntity;
import zxs.sino.elite.hub.service.app.ArticleService;
import zxs.sino.elite.hub.utils.UserContext;


@Service("articleService")
@RequiredArgsConstructor
public class ArticleServiceImpl extends MPJBaseServiceImpl<ArticleMapper, ArticleEntity> implements ArticleService {

    private final MongoTemplate mongoTemplate;

    private final UserMapper userMapper;

    private final ElasticsearchClient elasticsearchClient;

    /**
     * TODO 获取博客详情
     *
     * @param articleId
     * @return
     */
    @Override
    public ArticleVo getArticle4ArticleId(Long articleId) {
        return null;
    }

    /**
     * 存储博客
     * @param articleDto 博客表单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveOrUpdateArticle(ArticleForm articleDto) throws IOException {
        //1.将博客的基本信息存储到mysql中
        ArticleEntity articleEntity = new ArticleEntity();
        BeanUtils.copyProperties(articleDto, articleEntity);
        articleEntity.setAuthorId(UserContext.getUserId());
        String tagsStr = String.join(",", articleDto.getTags());
        articleEntity.setTags(tagsStr);
        this.saveOrUpdate(articleEntity);

        //2.将博客的正文信息存储到mongoDB中
        ArticleMongoEntity articleMongo = new ArticleMongoEntity();
        articleMongo.setArticleId(articleEntity.getArticleId());
        articleMongo.setContent(articleDto.getContent());
        mongoTemplate.save(articleMongo);

        //3.当博客类型为博客且状态为发表时，将信息存储到ES中
        if (ArticleType.isBlog(articleDto.getArticleType()) && articleDto.getStatus()){
            UserEntity userEntity = userMapper.selectById(UserContext.getUserId());

            ArticleVo articleVo = getArticleVo(articleDto, articleEntity, userEntity);

            IndexResponse response = elasticsearchClient.index(i -> i
                    .index(EsConstant.BOLG_INDEX)
                    .id(articleEntity.getArticleId().toString())
                    .document(articleVo)
            );

            if (!response.result().equals(Result.Created) && !response.result().equals(Result.Updated)){
                throw new RRException(BizCodeEnums.ARTICLE_PUBLISH_EXCEPTION.getMsg());
            }

            // TODO 将博客发表信息交给RabbitMQ完成消息发送。
        }

    }

    /**
     * 删除博客
     *
     * @param articleId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteArticle(Long articleId) throws IOException {
        // 1.将ES中id相同的数据删除掉
        DeleteResponse response = elasticsearchClient.delete(i -> i
                .index(EsConstant.BOLG_INDEX)
                .id(articleId.toString())
        );

        if (!response.result().equals(Result.Deleted) && !response.result().equals(Result.NotFound)){
            throw new RRException(BizCodeEnums.ARTICLE_REVOKE_EXCEPTION.getMsg());
        }

        // 2.将MongoDB中集合删除
        ArticleMongoEntity articleMongo = new ArticleMongoEntity();
        articleMongo.setArticleId(articleId);
        mongoTemplate.remove(articleMongo);

        // 3.将MySQL中数据删除
        this.removeById(articleId);
    }



    private static @NotNull ArticleVo getArticleVo(ArticleForm articleDto, ArticleEntity articleEntity, UserEntity userEntity) {
        ArticleVo articleVo = new ArticleVo();
        articleVo.setArticleId(articleEntity.getArticleId());
        articleVo.setAuthorId(UserContext.getUserId());
        articleVo.setAuthorName(userEntity.getNickname());
        articleVo.setAuthorUrl(userEntity.getAvatarUrl());
        articleVo.setTitle(articleDto.getTitle());
        articleVo.setCoverUrl(articleDto.getCoverUrl());
        articleVo.setSubtitle(articleDto.getSubtitle());
        articleVo.setContent(articleDto.getContent());
        articleVo.setPublishTime(new DateTime());
        return articleVo;
    }

}